package com.coder4j.auth.service;

import com.coder4j.auth.entity.AuthRefEntity;
import com.coder4j.enums.AuthRefTypeEnum;
import com.coder4j.auth.mapper.AuthRefMapper;
import com.coder4j.auth.vo.AuthRefQuery;
import com.coder4j.auth.vo.AuthRefVO;
import com.coder4j.starter.tools.util.ListUtils;
import com.coder4j.starter.web.BaseServiceImpl;
import lombok.NonNull;
import org.springframework.stereotype.Service;
import org.springframework.beans.BeanUtils;

import lombok.extern.slf4j.Slf4j;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 权限_关系
 * @author keller
 * @date 2024-05-07 18:10:11
 */
@Service
@Slf4j
public class AuthRefService extends BaseServiceImpl<AuthRefMapper,AuthRefEntity,AuthRefVO>  {

    @Resource
    private AuthRefMapper mapper;

    @Override
    public AuthRefVO entity2Vo(AuthRefEntity entity) {
        AuthRefVO vo = new AuthRefVO();
        BeanUtils.copyProperties(entity,vo);
        return vo;
    }

    @Override
    public AuthRefEntity vo2Entity(AuthRefVO vo) {
        AuthRefEntity entity = new AuthRefEntity();
        BeanUtils.copyProperties(vo, entity);
        return entity;
    }

    @Transactional
    public void changeOneToOneRef(AuthRefTypeEnum typeEnum, Long sourceId, Long targetId) {
        AuthRefQuery query = new AuthRefQuery();
        query.setSourceId(sourceId);
        query.setType(typeEnum.name());
        AuthRefEntity ref = this.baseQueryOne(query);
        //查询到已有关系
        if(ref != null){
            //关系未发生变动，不处理
            if(ref.getTargetId().equals(targetId)){
                return;
            }
            //目标关系为空，删除关系
            if(targetId == null){
                this.baseDeleteById(ref.getId());
            }else {
                //修改关系
                ref.setTargetId(targetId);
                this.baseSave(ref);
            }

            return;
        }
        //目标ID为空，不处理
        if(targetId == null){
            return;
        }
        //查询不到，添加
        ref = AuthRefEntity.buildRef(typeEnum,sourceId,targetId);
        this.baseSave(ref);
    }

    @Transactional
    public void changeOneToMoreRef(@NonNull AuthRefTypeEnum typeEnum, @NonNull Long sourceId, List<Long> targetIds) {
        AuthRefQuery query = new AuthRefQuery();
        query.setSourceId(sourceId);
        query.setType(typeEnum.name());
        List<AuthRefEntity> refList = this.baseQueryList(query);

        Set<Long> targetIdSet = ListUtils.isEmpty(targetIds) ? new HashSet<>() : new HashSet<>(targetIds);

        //当前没有关系
        if(ListUtils.isEmpty(refList)){
            //目标ID为空，不处理
            if(ListUtils.isEmpty(targetIdSet)){
                return;
            }
            //查询不到，添加
            this.saveBatch(typeEnum,sourceId,targetIdSet);
            return;
        }

        Set<Long> originalIdSet = refList.stream().map(AuthRefEntity::getTargetId).collect(Collectors.toSet());
        //关系未发生变动，不处理
        if(targetIdSet.size() == originalIdSet.size() && targetIdSet.containsAll(originalIdSet)){
            return;
        }
        //清空原有关系
        List<Long> idList = refList.stream().map(AuthRefEntity::getId).collect(Collectors.toList());
        this.baseDeleteByIds(idList);

        //目标关系为空，不处理
        if(targetIdSet.isEmpty()){
            return;
        }

        //批量添加
        this.saveBatch(typeEnum,sourceId,targetIdSet);
    }

    public Long getTargetId(@NonNull AuthRefTypeEnum typeEnum, @NonNull Long sourceId) {
        AuthRefQuery query = new AuthRefQuery();
        query.setType(typeEnum.name());
        query.setSourceId(sourceId);
        AuthRefEntity ref = this.baseQueryOne(query);
        return ref == null ? null : ref.getTargetId();
    }

    public List<Long> getTargetIds(@NonNull AuthRefTypeEnum typeEnum, @NonNull Long sourceId) {
        AuthRefQuery query = new AuthRefQuery();
        query.setType(typeEnum.name());
        query.setSourceId(sourceId);
        List<AuthRefEntity> list = this.baseQueryList(query);
        return ListUtils.isEmpty(list) ? null : list.stream().map(AuthRefEntity::getTargetId).collect(Collectors.toList());
    }

    private void saveBatch(AuthRefTypeEnum typeEnum, Long sourceId, Set<Long> targetIds){
        List<AuthRefEntity> list = new ArrayList<>();
        for (Long targetId : targetIds) {
            list.add(AuthRefEntity.buildRef(typeEnum, sourceId, targetId));
        }
        if(ListUtils.isEmpty(list)){
            return;
        }
        this.baseSaveList(list);
    }

}
